use validator::{Validate, HasLen};
use std::collections::HashMap;
use async_graphql::ErrorExtensionValues;

pub trait Valid {
    /// 验证是否通过
    fn is_valid(&self) -> bool;
    /// 错误消息转成map
    fn to_map(&self) -> Option<HashMap<&str, String>>;
    /// async-graphql 单个key的错误消息
    fn with_content(&self, e: &mut ErrorExtensionValues, k: &str, map: HashMap<&str, &str>);
}

impl<T> Valid for T where T: Validate {
    fn is_valid(&self) -> bool {
        self.validate().is_ok()
    }

    fn to_map(&self) -> Option<HashMap<&str, String>> {
        if self.is_valid() { return None; }
        let map = self.validate()
            .unwrap_err()
            .field_errors()
            .iter()
            .map(|(x, v)| {
                let z = v.first().unwrap();
                let s = if z.code == "length" {
                    let min = z.params["min"].as_u64().unwrap_or(0);
                    if min > z.params["value"].as_str().unwrap_or("").length() {
                        format!("输入内容不能小于{}", min)
                    } else {
                        format!("输入内容不能大于{}", z.params["max"].as_u64().unwrap())
                    }
                } else { "".to_string() };
                (*x, s)
            }).collect::<HashMap<_, _>>();

        Some(map)
    }

    fn with_content(&self, e: &mut ErrorExtensionValues, k: &str, map: HashMap<&str, &str>) {
        if let Some(o) = self.validate().unwrap_err().field_errors().get(k) {
            let z = o.first().unwrap();
            if let Some(s) = map.get(&*z.code) {
                if z.code == "length" {
                    let min = z.params["min"].as_u64().unwrap();
                    let max = z.params["max"].as_u64().unwrap();
                    e.set(k, format!("{}{}到{}位！", s, min, max))
                } else {
                    e.set(k, *s);
                }
            }
        }
    }
}